<!DOCTYPE html>
<html>
<head>
    

    

    



    <meta charset="utf-8">
    
    
    
    <title>Android架构组件(8)-Paging | 随手记 | 不积跬步无以至千里</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#1c9d5c">
    
    
    <meta name="keywords" content="Android,Architecture Components">
    <meta name="description" content="分页库使您的应用程序能够更轻松地根据需要从数据源加载信息，而不会使设备过载或等待太长的数据库查询时间。 概览 许多应用程序可以处理大量数据，但只需要随时加载和显示一小部分数据。 一个应用程序可能有数千个可能显示的项目，但它可能只需要一次访问几十个项目。 如果应用程序不小心，它最终可能会请求实际不需要的数据，从而给设备和网络带来性能负担。 如果数据与远程数据库存储或同步，则这也会降低应用速度并浪费用">
<meta name="keywords" content="Android,Architecture Components">
<meta property="og:type" content="article">
<meta property="og:title" content="Android架构组件(8)-Paging">
<meta property="og:url" content="http://yoursite.com/2017/10/12/architecture-paging/index.html">
<meta property="og:site_name" content="随手记">
<meta property="og:description" content="分页库使您的应用程序能够更轻松地根据需要从数据源加载信息，而不会使设备过载或等待太长的数据库查询时间。 概览 许多应用程序可以处理大量数据，但只需要随时加载和显示一小部分数据。 一个应用程序可能有数千个可能显示的项目，但它可能只需要一次访问几十个项目。 如果应用程序不小心，它最终可能会请求实际不需要的数据，从而给设备和网络带来性能负担。 如果数据与远程数据库存储或同步，则这也会降低应用速度并浪费用">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="http://yoursite.com/2017/10/12/architecture-paging/paging-threading.gif">
<meta property="og:image" content="http://yoursite.com/2017/10/12/architecture-paging/paging-network-or-database.png">
<meta property="og:image" content="http://yoursite.com/2017/10/12/architecture-paging/paging-network-plus-database.png">
<meta property="og:updated_time" content="2018-04-15T09:24:43.184Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Android架构组件(8)-Paging">
<meta name="twitter:description" content="分页库使您的应用程序能够更轻松地根据需要从数据源加载信息，而不会使设备过载或等待太长的数据库查询时间。 概览 许多应用程序可以处理大量数据，但只需要随时加载和显示一小部分数据。 一个应用程序可能有数千个可能显示的项目，但它可能只需要一次访问几十个项目。 如果应用程序不小心，它最终可能会请求实际不需要的数据，从而给设备和网络带来性能负担。 如果数据与远程数据库存储或同步，则这也会降低应用速度并浪费用">
<meta name="twitter:image" content="http://yoursite.com/2017/10/12/architecture-paging/paging-threading.gif">
    
        <link rel="alternate" type="application/atom+xml" title="随手记" href="/atom.xml">
    
    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="/css/style.css?v=1.7.2">
    <script>window.lazyScripts=[]</script>

    <!-- custom head -->
    

</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu" class="hide" >
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap" style="background-image:url(/img/brand.jpg)">
      <div class="brand">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/avatar.jpg">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">马建</h5>
          <a href="mailto:markjoker@126.com" title="markjoker@126.com" class="mail">markjoker@126.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/"  >
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/archives"  >
                <i class="icon icon-lg icon-archives"></i>
                归档
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/tags"  >
                <i class="icon icon-lg icon-tags"></i>
                标签
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/categories"  >
                <i class="icon icon-lg icon-th-list"></i>
                分类
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="https://github.com/markjoker" target="_blank" >
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://www.weibo.com/markjoker" target="_blank" >
                <i class="icon icon-lg icon-weibo"></i>
                微博
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/cv"  >
                <i class="icon icon-lg icon-file"></i>
                简历
              </a>
            </li>
        
      </ul>
    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">Android架构组件(8)-Paging</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">Android架构组件(8)-Paging</h1>
        <h5 class="subtitle">
            
                <time datetime="2017-10-12T09:23:07.000Z" itemprop="datePublished" class="page-time">
  2017-10-12
</time>


            
        </h5>
    </div>

    


</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap post-toc-shrink" id="post-toc">
            <h4>目录</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#概览"><span class="post-toc-number">1.</span> <span class="post-toc-text">概览</span></a></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#功能"><span class="post-toc-number">2.</span> <span class="post-toc-text">功能</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#定义如何获取数据"><span class="post-toc-number">2.1.</span> <span class="post-toc-text">定义如何获取数据</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#将数据加载到内存中"><span class="post-toc-number">2.2.</span> <span class="post-toc-text">将数据加载到内存中</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#在用户界面中呈现数据"><span class="post-toc-number">2.3.</span> <span class="post-toc-text">在用户界面中呈现数据</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#观察数据更新"><span class="post-toc-number">2.4.</span> <span class="post-toc-text">观察数据更新</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#创建一个数据流"><span class="post-toc-number">2.5.</span> <span class="post-toc-text">创建一个数据流</span></a></li></ol></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#数据库示例"><span class="post-toc-number">3.</span> <span class="post-toc-text">数据库示例</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#使用LiveData观察分页数据"><span class="post-toc-number">3.1.</span> <span class="post-toc-text">使用LiveData观察分页数据</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#使用RxJava2观察分页数据"><span class="post-toc-number">3.2.</span> <span class="post-toc-text">使用RxJava2观察分页数据</span></a></li></ol></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#选择一个数据加载架构"><span class="post-toc-number">4.</span> <span class="post-toc-text">选择一个数据加载架构</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#网络或数据库"><span class="post-toc-number">4.1.</span> <span class="post-toc-text">网络或数据库</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#网络和数据库"><span class="post-toc-number">4.2.</span> <span class="post-toc-text">网络和数据库</span></a></li></ol></li></ol>
        </nav>
    </aside>


<article id="post-architecture-paging"
  class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">Android架构组件(8)-Paging</h1>
        <div class="post-meta">
            <time class="post-time" title="2017-10-12 17:23:07" datetime="2017-10-12T09:23:07.000Z"  itemprop="datePublished">2017-10-12</time>

            


            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style='display:none'>
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <p>分页库使您的应用程序能够更轻松地根据需要从数据源加载信息，而不会使设备过载或等待太长的数据库查询时间。</p>
<h1 id="概览"><a href="#概览" class="headerlink" title="概览"></a>概览</h1><hr>
<p>许多应用程序可以处理大量数据，但只需要随时加载和显示一小部分数据。 一个应用程序可能有数千个可能显示的项目，但它可能只需要一次访问几十个项目。 如果应用程序不小心，它最终可能会请求实际不需要的数据，从而给设备和网络带来性能负担。 如果数据与远程数据库存储或同步，则这也会降低应用速度并浪费用户的数据计划。</p>
<p>尽管现有的Android API允许在内容中进行分页，但它们带来了明显的限制和缺陷：</p>
<ul>
<li><code>CursorAdapter</code>可以更轻松地将数据库查询结果映射到<code>ListView</code>项目，但它会在UI线程上运行数据库查询，并使用<code>Cursor</code>无效地页面内容。 有关使用<code>CursorAdapter</code>的缺点的更多详细信息，请参阅博客文章Android上的大型数据库查询。</li>
<li><code>AsyncListUtil</code>允许将基于位置的数据分页到<code>RecyclerView</code>中，但不允许进行非定位分页，并强制在可数数据集中使用空值作为占位符。</li>
</ul>
<p>新的分页库解决了这些问题。该库包含几个类，以便在需要时简化请求数据的过程。这些类还可以与现有的体系结构组件（如Room）无缝协作。</p>
<h1 id="功能"><a href="#功能" class="headerlink" title="功能"></a>功能</h1><hr>
<p>分页库的一组类允许您完成本节中显示的任务。</p>
<h2 id="定义如何获取数据"><a href="#定义如何获取数据" class="headerlink" title="定义如何获取数据"></a>定义如何获取数据</h2><p>使用<code>DataSource</code>类定义您需要从中提取分页数据的数据源。根据你需要访问你的数据的方式，你可以扩展它的一个子类：</p>
<ul>
<li>如果您加载的页面嵌入了下一个/上一个键，请使用<code>PageKeyedDataSource</code>。例如，如果您从网络中提取社交媒体帖子，则可能需要将下一个代码从一个加载传递到后续加载。</li>
<li>如果您需要使用项目N中的数据来获取项目N + 1，请使用<code>ItemKeyedDataSource</code>。例如，如果您为讨论应用程序提取线索评论，则可能需要传递一条评论的标识以获取下一条评论的内容。</li>
<li>如果您需要从您在数据存储中选择的任何位置获取数据页面，请使用<code>PositionalDataSource</code>。 此类支持从您选择的任何位置开始请求一组数据项，如“返回从位置1200开始的20个数据项”。</li>
</ul>
<p>如果使用<code>Room</code>持久化库来管理数据，它可以自动生成一个·DataSource.Factory·来为您生成·PositionalDataSource·的实例。例如：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Query</span>(<span class="string">"select * from users WHERE age &gt; :age order by name DESC, id ASC"</span>)</span><br><span class="line">DataSource.<span class="function">Factory&lt;Integer, User&gt; <span class="title">usersOlderThan</span><span class="params">(<span class="keyword">int</span> age)</span></span>;</span><br></pre></td></tr></table></figure></p>
<h2 id="将数据加载到内存中"><a href="#将数据加载到内存中" class="headerlink" title="将数据加载到内存中"></a>将数据加载到内存中</h2><p><code>PagedList</code>类从<code>DataSource</code>加载数据。 您可以配置一次加载多少数据，以及预取多少数据，从而最大限度地缩短用户等待数据加载的时间。 该类可以向其他类提供更新信号，例如<code>RecyclerView.Adapter</code>，允许您在页面中加载数据时更新<code>RecyclerView</code>的内容。<br>根据您的应用程序的体系结构，您有几个使用PagedList类的选项。要了解更多信息，请参阅<a href="https://developer.android.com/topic/libraries/architecture/paging.html#choose-data-loading-arch" target="_blank" rel="noopener">选择数据加载体系结构</a>。</p>
<h2 id="在用户界面中呈现数据"><a href="#在用户界面中呈现数据" class="headerlink" title="在用户界面中呈现数据"></a>在用户界面中呈现数据</h2><p><code>PagedListAdapter</code>类是一个<code>RecyclerView.Adapter</code>的实现，用于呈现<code>PagedList</code>中的数据。 例如，当加载新页面时，<code>PagedListAdapter</code>向<code>RecyclerView</code>指示数据已到达; 这可以让<code>RecyclerView</code>用实际项目替换任何占位符，执行适当的动画。 <code>PagedListAdapter</code>还使用后台线程来计算从一个<code>PagedList</code>到下一个更改的更改（例如，当数据库更改生成具有更新数据的新<code>PagedList</code>时），并根据需要调用<code>notifyItem ...（）</code>方法以更新列表内容。 <code>RecyclerView</code>然后执行必要的更改。 例如，如果项目在<code>PagedList</code>版本之间改变位置，则<code>RecyclerView</code>会将该项目移动到列表中的新位置。</p>
<h2 id="观察数据更新"><a href="#观察数据更新" class="headerlink" title="观察数据更新"></a>观察数据更新</h2><p>分页库提供以下类来构建能够实时更新的<code>PagedList</code>容器：</p>
<ul>
<li><p><strong>LivePagedListBuilder</strong><br>该类从您提供的<code>DataSource.Factory</code>生成一个<code>LiveData &lt;PagedList&gt;</code>。 如果使用<code>Room</code>持久性库来管理数据库，则<code>DAO</code>可以使用<code>PositionalDataSource</code>为您生成<code>DataSource.Factory</code>，如以下示例所示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">LiveData&lt;PagedList&lt;Item&gt;&gt; pagedItems =</span><br><span class="line">        LivePagedListBuilder(myDataSource, <span class="comment">/* page size */</span> <span class="number">50</span>)</span><br><span class="line">                .setFetchExecutor(myNetworkExecutor)</span><br><span class="line">                .build();</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>RxPagedListBuilder</strong><br>该类提供了与<code>LivePagedListBuilder</code>类似的基于<code>RxJava2</code>的功能。 该类由图书馆基于<code>RxJava2</code>的工件<code>android.arch.paging:rxjava2:1.0.0-alpha1</code>。 使用这个类，您可以在<code>PagedList</code>的实现中构造<code>Flowable</code>和<code>Observable</code>对象，如以下代码片段所示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Flowable&lt;PagedList&lt;Item&gt;&gt; pagedItems =</span><br><span class="line">        RxPagedListBuilder(myDataSource, <span class="comment">/* page size */</span> <span class="number">50</span>)</span><br><span class="line">                .setFetchScheduler(myNetworkScheduler)</span><br><span class="line">                .buildFlowable(BackpressureStrategy.LATEST);</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="创建一个数据流"><a href="#创建一个数据流" class="headerlink" title="创建一个数据流"></a>创建一个数据流</h2><p><code>Paging Library</code>的组件组织来自后台线程生成器的数据流，并在UI线程上呈现。 例如，在数据库中插入新项目时，数据源将失效，并且<code>LiveData &lt;PagedList&gt;</code>或<code>Flowable &lt;PagedList&gt;</code>会在后台线程上生成新的<code>PagedList</code>。<br><figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/2017/10/12/architecture-paging/paging-threading.gif" alt="t1" title="">
                </div>
                <div class="image-caption">t1</div>
            </figure></p>
<p><font style="font-size:14px">图1.分页库组件在后台线程中完成大部分工作，所以它们不会给UI线程造成负担。</font><br>新创建的<code>PagedList</code>被发送到UI线程的<code>PagedListAdapter</code>。 <code>PagedListAdapter</code>然后在后台线程上使用<code>DiffUtil</code>来计算当前列表和新列表之间的差异。 比较完成后，<code>PagedListAdapter</code>使用列表差异信息对<code>RecyclerView.Adapter.notifyItemInserted()</code>进行适当调用，以表示插入了新项目。</p>
<p>UI线程上的<code>RecyclerView</code>知道它只需绑定一个新项目，并将其动画显示在屏幕上。</p>
<h1 id="数据库示例"><a href="#数据库示例" class="headerlink" title="数据库示例"></a>数据库示例</h1><hr>
<p>以下代码片段显示了将所有片段一起使用的几种可能方式.</p>
<h2 id="使用LiveData观察分页数据"><a href="#使用LiveData观察分页数据" class="headerlink" title="使用LiveData观察分页数据"></a>使用LiveData观察分页数据</h2><p>下面的代码片段显示了所有一起工作的部分。随着用户在数据库中的添加，删除或更改，<code>RecyclerView</code>的内容会自动而有效地更新：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Dao</span></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">UserDao</span> </span>&#123;</span><br><span class="line">    <span class="comment">// The Integer type parameter tells Room to use a PositionalDataSource</span></span><br><span class="line">    <span class="comment">// object, with position-based loading under the hood.</span></span><br><span class="line">    <span class="meta">@Query</span>(<span class="string">"SELECT * FROM user ORDER BY lastName ASC"</span>)</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> DataSource.<span class="function">Factory&lt;Integer, User&gt; <span class="title">usersByLastName</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyViewModel</span> <span class="keyword">extends</span> <span class="title">ViewModel</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> LiveData&lt;PagedList&lt;User&gt;&gt; usersList;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyViewModel</span><span class="params">(UserDao userDao)</span> </span>&#123;</span><br><span class="line">        usersList = <span class="keyword">new</span> LivePagedListBuilder&lt;&gt;(</span><br><span class="line">                userDao.usersByLastName(), <span class="comment">/* page size */</span> <span class="number">20</span>).build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> UserAdapter&lt;User&gt; mAdapter;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedState);</span><br><span class="line">        MyViewModel viewModel = ViewModelProviders.of(<span class="keyword">this</span>).get(MyViewModel.class);</span><br><span class="line">        RecyclerView recyclerView = findViewById(R.id.user_list);</span><br><span class="line">        mAdapter = <span class="keyword">new</span> UserAdapter();</span><br><span class="line">        viewModel.usersList.observe(<span class="keyword">this</span>, pagedList -&gt;</span><br><span class="line">                mAdapter.submitList(pagedList));</span><br><span class="line">        recyclerView.setAdapter(mAdapter);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserAdapter</span> <span class="keyword">extends</span> <span class="title">PagedListAdapter</span>&lt;<span class="title">User</span>, <span class="title">UserViewHolder</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">UserAdapter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(DIFF_CALLBACK);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onBindViewHolder</span><span class="params">(UserViewHolder holder, <span class="keyword">int</span> position)</span> </span>&#123;</span><br><span class="line">        User user = getItem(position);</span><br><span class="line">        <span class="keyword">if</span> (user != <span class="keyword">null</span>) &#123;</span><br><span class="line">            holder.bindTo(user);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// Null defines a placeholder item - PagedListAdapter will automatically invalidate</span></span><br><span class="line">            <span class="comment">// this row when the actual object is loaded from the database</span></span><br><span class="line">            holder.clear();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> DiffUtil.ItemCallback&lt;User&gt; DIFF_CALLBACK =</span><br><span class="line">            <span class="keyword">new</span> DiffUtil.ItemCallback&lt;User&gt;() &#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">areItemsTheSame</span><span class="params">(@NonNull User oldUser, @NonNull User newUser)</span> </span>&#123;</span><br><span class="line">            <span class="comment">// User properties may have changed if reloaded from the DB, but ID is fixed</span></span><br><span class="line">            <span class="keyword">return</span> oldUser.getId() == newUser.getId();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">areContentsTheSame</span><span class="params">(@NonNull User oldUser, @NonNull User newUser)</span> </span>&#123;</span><br><span class="line">            <span class="comment">// <span class="doctag">NOTE:</span> if you use equals, your object must properly override Object#equals()</span></span><br><span class="line">            <span class="comment">// Incorrectly returning false here will result in too many animations.</span></span><br><span class="line">            <span class="keyword">return</span> oldUser.equals(newUser);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="使用RxJava2观察分页数据"><a href="#使用RxJava2观察分页数据" class="headerlink" title="使用RxJava2观察分页数据"></a>使用RxJava2观察分页数据</h2><p>如果您更喜欢使用<code>RxJava2</code>而不是<code>LiveData</code>，则可以改为创建<code>Observable</code>或<code>Flowable</code>对象：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyViewModel</span> <span class="keyword">extends</span> <span class="title">ViewModel</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> Flowable&lt;PagedList&lt;User&gt;&gt; usersList;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyViewModel</span><span class="params">(UserDao userDao)</span> </span>&#123;</span><br><span class="line">        usersList = <span class="keyword">new</span> RxPagedListBuilder&lt;&gt;(userDao.usersByLastName(),</span><br><span class="line">                <span class="comment">/* page size */</span> <span class="number">50</span>).buildFlowable(BackpressureStrategy.LATEST);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>然后，您可以使用以下代码片段中的代码开始和停止观察数据：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> UserAdapter&lt;User&gt; mAdapter;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> CompositeDisposable mDisposable = <span class="keyword">new</span> CompositeDisposable();</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedState);</span><br><span class="line">        MyViewModel viewModel = ViewModelProviders.of(<span class="keyword">this</span>).get(MyViewModel.class);</span><br><span class="line">        RecyclerView recyclerView = findViewById(R.id.user_list);</span><br><span class="line">        mAdapter = <span class="keyword">new</span> UserAdapter();</span><br><span class="line">        recyclerView.setAdapter(mAdapter);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStart</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onStart();</span><br><span class="line">        myDisposable.add(mViewModel.usersList.subscribe(flowableList -&gt;</span><br><span class="line">                mAdapter.submitList(flowableList)));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onStop();</span><br><span class="line">        mDisposable.clear();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>对于基于<code>RxJava2</code>的解决方案，<code>UserDao</code>和<code>UserAdapter</code>的代码与基于<code>LiveData</code>的解决方案的代码相同。</p>
<h1 id="选择一个数据加载架构"><a href="#选择一个数据加载架构" class="headerlink" title="选择一个数据加载架构"></a>选择一个数据加载架构</h1><hr>
<p>使用分页库来做数据的分页主要有两种方式：</p>
<h2 id="网络或数据库"><a href="#网络或数据库" class="headerlink" title="网络或数据库"></a>网络或数据库</h2><p>首先，您可以从单一来源进行分页 - 本地存储或网络。在这种情况下，使用<code>LiveData &lt;PagedList&gt;</code>将加载的数据馈送到UI中，如上面的示例中所示。<br>要指定数据源，请将<code>DataSource.Factory</code>传递给<code>LivePagedListBuilder</code>。<br><figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/2017/10/12/architecture-paging/paging-network-or-database.png" alt="t1" title="">
                </div>
                <div class="image-caption">t1</div>
            </figure></p>
<p><font style="font-size:14px">图2.单一数据源提供DataSource.Factory来加载内容。</font><br>当观察数据库时，数据库在发生内容更改时将“推送”新的<code>PagedList</code>。 在网络分页情况下（当后端不发送更新时），像刷卡到刷新这样的信号可以通过使当前数据源无效来“拉”新的分页列表。 这将异步刷新所有数据。<br><a href="https://github.com/googlesamples/android-architecture-components/blob/master/PagingWithNetworkSample/README.md" target="_blank" rel="noopener">PagingWithNetworkSample</a>中的内存+网络存储库实现显示如何在处理刷新刷新，网络错误和重试时使用<code>Retrofit</code>实现网络<code>DataSource.Factory</code>。</p>
<h2 id="网络和数据库"><a href="#网络和数据库" class="headerlink" title="网络和数据库"></a>网络和数据库</h2><p>在第二种情况下，您可以从本地存储页面进行寻址，本地存储页面本身从网络中寻找额外的数据 这通常是为了最大限度地减少网络负载并提供更好的低连接体验 - 数据库被用作存储在后端数据的缓存。<br>在这种情况下，使用<code>LiveData &lt;PagedList&gt;</code>来从数据库中分页内容，并将<code>BoundaryCallback</code>传递给<code>LivePagedListBuilder</code>以观察数据不足信号。<br><figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/2017/10/12/architecture-paging/paging-network-plus-database.png" alt="t3" title="">
                </div>
                <div class="image-caption">t3</div>
            </figure></p>
<p><font style="font-size:14px">数据库是网络数据的缓存 - UI从数据库加载数据，并在数据不足时从网络加载到数据库时发送信号。</font><br>然后将这些回调连接到网络请求，这些请求将直接将数据存储在数据库中。用户界面订阅了数据库更新，所以新的内容自动流向任何观察用户界面。<br><a href="https://github.com/googlesamples/android-architecture-components/blob/master/PagingWithNetworkSample/README.md" target="_blank" rel="noopener">PagingWithNetworkSample</a>中的数据库+网络存储库显示了如何使用Retrofit实现网络<code>BoundaryCallback</code>，同时处理刷卡刷新，网络错误和重试。</p>

        </div>

        <blockquote class="post-copyright">
    
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2018-04-15T09:24:43.184Z" itemprop="dateUpdated">2018-04-15 17:24:43</time>
</span><br>


        
        如有错误，请留言指正。
        
    </div>
    
    <footer>
        <a href="http://yoursite.com">
            <img src="/img/avatar.jpg" alt="马建">
            马建
        </a>
    </footer>
</blockquote>

        
<div class="page-reward">
    <a id="rewardBtn" href="javascript:;" class="page-reward-btn waves-effect waves-circle waves-light">赏</a>
</div>



        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Android/">Android</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Architecture-Components/">Architecture Components</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://yoursite.com/2017/10/12/architecture-paging/&title=《Android架构组件(8)-Paging》 — 随手记&pic=http://yoursite.com/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://yoursite.com/2017/10/12/architecture-paging/&title=《Android架构组件(8)-Paging》 — 随手记&source=desc" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://yoursite.com/2017/10/12/architecture-paging/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《Android架构组件(8)-Paging》 — 随手记&url=http://yoursite.com/2017/10/12/architecture-paging/&via=http://yoursite.com" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://yoursite.com/2017/10/12/architecture-paging/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between">
  
    <div class="waves-block waves-effect prev">
      <a href="/2018/03/28/react-native-https/" id="post-prev" class="post-nav-link">
        <div class="tips"><i class="icon icon-angle-left icon-lg icon-pr"></i> Prev</div>
        <h4 class="title">React Native 自签名Https处理</h4>
      </a>
    </div>
  

  
    <div class="waves-block waves-effect next">
      <a href="/2017/10/11/architecture-room/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">Android架构组件(七)-Room</h4>
      </a>
    </div>
  
</nav>



    














</article>

<div id="reward" class="page-modal reward-lay">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <h3 class="reward-title">
        <i class="icon icon-quote-left"></i>
        谢谢大爷~
        <i class="icon icon-quote-right"></i>
    </h3>
    <div class="reward-content">
        
        <div class="reward-code">
            <img id="rewardCode" src="/img/wechat.jpg" alt="打赏二维码">
        </div>
        
        <label class="reward-toggle">
            <input id="rewardToggle" type="checkbox" class="reward-toggle-check"
                data-wechat="/img/wechat.jpg" data-alipay="/img/alipay.jpg">
            <div class="reward-toggle-ctrol">
                <span class="reward-toggle-item wechat">微信</span>
                <span class="reward-toggle-label"></span>
                <span class="reward-toggle-item alipay">支付宝</span>
            </div>
        </label>
        
    </div>
</div>



</div>

        <footer class="footer">
    <div class="top">
        
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        站点总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        站点总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            
                <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            
            <span>博客内容遵循 <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p><span>马建 &copy; 2015 - 2019</span>
            <span>
                
            </span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://yoursite.com/2017/10/12/architecture-paging/&title=《Android架构组件(8)-Paging》 — 随手记&pic=http://yoursite.com/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://yoursite.com/2017/10/12/architecture-paging/&title=《Android架构组件(8)-Paging》 — 随手记&source=desc" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://yoursite.com/2017/10/12/architecture-paging/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《Android架构组件(8)-Paging》 — 随手记&url=http://yoursite.com/2017/10/12/architecture-paging/&via=http://yoursite.com" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://yoursite.com/2017/10/12/architecture-paging/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: true };


</script>

<script src="/js/main.min.js?v=1.7.2"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="/js/search.min.js?v=1.7.2" async></script>






<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>



<script>
(function() {
    var OriginTitile = document.title, titleTime;
    document.addEventListener('visibilitychange', function() {
        if (document.hidden) {
            document.title = '随手记';
            clearTimeout(titleTime);
        } else {
            document.title = '随手记';
            titleTime = setTimeout(function() {
                document.title = OriginTitile;
            },2000);
        }
    });
})();
</script>



</body>
</html>
